/*
 *
 *  Smart pointer
 *
 *
 */
#include <iostream>
using namespace std;

template< class T>
class SmartPointer{
    public:
    T *data;
    unsigned *ref_count;
    
    SmartPointer( T *d ){
        data = d;
        ref_count = new unsigned(1);
        cout << "called conversion constructor" << endl;
    }
    
    SmartPointer( SmartPointer & p ){
        data = p.data;
        ref_count = p.ref_count;
        (*ref_count)++;
        cout << "called copy constructor" << endl;
    }
  
    ~SmartPointer(){
        remove();
        cout<<"destructor: "; 
        if(ref_count)
            cout << ",ref_count: "<< *ref_count;
        else
            cout << "counter pointer is NULL";
        cout << endl;
    }

    SmartPointer & operator=( SmartPointer &p ){
        if( this==&p )
            return *this;

        remove();

        data = p.data;
        ref_count = p.ref_count;
        (*ref_count)++;
        cout << "set input pointer by op = : "<< *p.data << endl;
        return *this;
    }

    const unsigned getRefcount()const{
        return *ref_count;
    }
    
    const T & operator*()const{
        return *data;
    }
    
    T & operator*(){
        return *data;
    }

    private:
    void remove(){
        if(ref_count)
            (*ref_count)--;

        if( data && ref_count ){
            if( *ref_count==0 ){
                cout << "del value: " << *data << endl;
                delete data;
                delete ref_count;
                data = NULL;
                ref_count = NULL;
            }
        }
    }


};

int main(){
    
    SmartPointer<int> a( new int(10) );
    cout <<"*operator: "<< *a <<",refcount: "<< a.getRefcount() << endl;

    SmartPointer<int> cc = a; 
    cout <<"cc->a: "<< *cc <<",refcount: "<< cc.getRefcount()<< endl;
  
    SmartPointer<int> dd = a; 
    cout <<"dd->a: "<< *dd <<",refcount: "<< dd.getRefcount()<< endl;

    cout <<"a status: "<< *a <<",refcount: "<< a.getRefcount() << endl;
    SmartPointer<int> b( new int(20) );
    cout <<"b status: "<< *b <<",refcount: "<< b.getRefcount() << endl;
    b = a; 
    cout <<"b status after point to a: "<< *b <<",refcount: "<< b.getRefcount() << endl;
}
